/*
 * Sales Data Controller Project.
 * Copyright (C) 2011 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see
 * http://www.gnu.org/licenses/.
 */

package be.fedict.sdc.vsc.admin;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class AppletManager {

	private static final Log LOG = LogFactory.getLog(AppletManager.class);

	private List<AppletManagerListener> listeners;

	public AppletManager() {
		this.listeners = new LinkedList<AppletManagerListener>();
	}

	public void addListener(AppletManagerListener listener) {
		this.listeners.add(listener);
	}

	public void loadApplet(int readerNumber) throws IOException {
		LOG.debug("load applet on reader: " + readerNumber);

		/*
		 * Copy CAP resource to a temp file.
		 */
		InputStream appletCapInputStream = AppletManager.class
				.getResourceAsStream("/vsc-applet.cap");
		File capFile = File.createTempFile("vsc-applet-", ".cap");
		capFile.deleteOnExit();
		FileUtils.copyInputStreamToFile(appletCapInputStream, capFile);
		LOG.debug("tmp CAP file: " + capFile.getAbsolutePath());

		/*
		 * Generate the gpshell config file.
		 */
		Configuration configuration = new Configuration();
		configuration.setClassForTemplateLoading(AppletManager.class, "/");
		Template template = configuration
				.getTemplate("gpshell-gemalto-gemxpresso.ftl");
		Map<String, Object> rootMap = new HashMap<String, Object>();
		rootMap.put("readerNumber", readerNumber);
		rootMap.put("capFile", capFile.getAbsolutePath());

		File gpshellConfigFile = File
				.createTempFile("gpshell-config-", ".conf");
		gpshellConfigFile.deleteOnExit();
		Writer out = new FileWriter(gpshellConfigFile);
		try {
			template.process(rootMap, out);
		} catch (TemplateException e) {
			throw new IOException("template error: " + e.getMessage(), e);
		}
		LOG.debug("gpshell tmp config file: "
				+ gpshellConfigFile.getAbsolutePath());

		/*
		 * Run gpshell.
		 */
		ProcessBuilder processBuilder = new ProcessBuilder("gpshell",
				gpshellConfigFile.getAbsolutePath());
		processBuilder.redirectErrorStream(true);
		Process process = processBuilder.start();
		InputStream inputStream = process.getInputStream();
		ProcessOutputProcessor processOutputProcessor = new ProcessOutputProcessor(
				inputStream);
		processOutputProcessor.start();
		int exitValue;
		try {
			exitValue = process.waitFor();
		} catch (InterruptedException e) {
			throw new IOException("interrupted exception: " + e.getMessage());
		}
		LOG.debug("exit value: " + exitValue);
		if (0 != exitValue) {
			throw new IOException("gpshell exit value: " + exitValue);
		}
	}

	private class ProcessOutputProcessor extends Thread {
		private final InputStream inputStream;

		public ProcessOutputProcessor(InputStream inputStream) {
			this.inputStream = inputStream;
		}

		@Override
		public void run() {
			try {
				doOutput();
			} catch (IOException e) {
				throw new RuntimeException("IO error: " + e.getMessage());
			}
		}

		private void doOutput() throws IOException {
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					this.inputStream));
			String line;
			while ((line = reader.readLine()) != null) {
				for (AppletManagerListener listener : AppletManager.this.listeners) {
					listener.appendMessage(line);
				}
			}
			reader.close();
		}
	}
}
